using System.Diagnostics;
using System.Data;
using System.Collections;
using Microsoft.VisualBasic;
using System.Collections.Generic;
using System;
using Microsoft.ReportingServices.ReportRendering;
using System.Drawing;
using System.Web;
using System.Text;

namespace CustomExcelRenderCS
{
	public class Renderer:  Microsoft.ReportingServices.ReportRendering.IRenderingExtension
	{
        internal static Microsoft.ReportingServices.Interfaces.CreateAndRegisterStream mCreateAndRegisterStream;
        internal static Report mReport; 
        internal static string srvPath;
        internal static string reportFolder; 
        internal static double pageHeaderHeight;
        internal static System.IO.Stream s = null;
        internal static System.IO.StreamWriter sw = null;
        internal static System.Collections.Specialized.NameValueCollection mDeviceInfo;

        private const string PageDefinition = "<html xmlns:o='urn:schemas-microsoft-com:office:office' " +
                        "xmlns:x='urn:schemas-microsoft-com:office:excel'" +
                        "xmlns='http://www.w3.org/TR/REC-html40'>";
        internal const Double standardCellWidth = 0.5;

        private string _pagePrintDef = "";
        private static double pageFooterWidth;
        private  string pageFooterLeft="";
        private  string pageFooterCenter="";
        private  string pageFooterRight="";
        private  bool isWidePage = false;

        private static string currentTableName;
        internal static double globalTrackingRow;

        private Microsoft.ReportingServices.ReportRendering.PageSection pageHeader, pageFooter;

        internal static bool isInSubreportContext = false;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="streamName"></param>
        /// <param name="report"></param>
        /// <param name="reportServerParameters"></param>
        /// <param name="deviceInfo"></param>
        /// <param name="clientCapabilities"></param>
        /// <param name="evaluateHeaderFooterExpressions"></param>
        /// <param name="createAndRegisterStream"></param>
        /// <returns></returns>
		public bool RenderStream(string streamName, Microsoft.ReportingServices.ReportRendering.Report report, System.Collections.Specialized.NameValueCollection reportServerParameters, System.Collections.Specialized.NameValueCollection deviceInfo, System.Collections.Specialized.NameValueCollection clientCapabilities, Microsoft.ReportingServices.ReportRendering.EvaluateHeaderFooterExpressions evaluateHeaderFooterExpressions, Microsoft.ReportingServices.Interfaces.CreateAndRegisterStream createAndRegisterStream)
		{
			return false;
		}
		
		/// <summary>
		/// 
		/// </summary>
		/// <param name="report"></param>
		/// <param name="reportServerParameters"></param>
		/// <param name="deviceInfo"></param>
		/// <param name="clientCapabilities"></param>
		/// <param name="evaluateHeaderFooterExpressions"></param>
		/// <param name="createAndRegisterStream"></param>
		/// <returns></returns>
		public bool Render(Microsoft.ReportingServices.ReportRendering.Report report, System.Collections.Specialized.NameValueCollection reportServerParameters, System.Collections.Specialized.NameValueCollection deviceInfo, System.Collections.Specialized.NameValueCollection clientCapabilities, Microsoft.ReportingServices.ReportRendering.EvaluateHeaderFooterExpressions evaluateHeaderFooterExpressions, Microsoft.ReportingServices.Interfaces.CreateAndRegisterStream createAndRegisterStream)
		{
            try
            {
                // set variables for later use, mainly image class
                mCreateAndRegisterStream = createAndRegisterStream;
                mReport = report;
                mDeviceInfo = deviceInfo;

                // init hash table for reportitemhashtable
                reportItemHashTable = new Hashtable();
                reportRenderCache = new ReportRenderCache();

                //s = createAndRegisterStream(report.Name, "htm", System.Text.Encoding.UTF8, "text/html", true, Microsoft.ReportingServices.Interfaces.StreamOper.CreateAndRegister);
                s = createAndRegisterStream(report.Name, "xls", System.Text.Encoding.UTF8, "application/vnd.ms-excel", true, Microsoft.ReportingServices.Interfaces.StreamOper.CreateAndRegister);
              
                sw = new System.IO.StreamWriter(s);

                Microsoft.ReportingServices.ReportRendering.PageReportItems pageReportItems = new Microsoft.ReportingServices.ReportRendering.PageReportItems();
                evaluateHeaderFooterExpressions(1, 1, report, pageReportItems, out pageHeader, out pageFooter);

                // prepage global variables used byt report rendering
                prepareReportRenderGlobalVariables(report);
                preparePageFooterItems();
                 
                // init page header
                sw.WriteLine(PageDefinition);

                // add style to page, make page footer available when print
                sw.WriteLine(getPageStyle());

                //sw.WriteLine(getPageScript());

                // define print style: if landscape 
                if (isWidePage == true)
                    sw.WriteLine(pagePrintDef);

                // body
                sw.WriteLine("<body>");

                #region page header 
                // Process items in page header 
                 
                for (int i = 0; i <= pageHeader.ReportItemCollection.Count - 1; i++)
                {
                    string str = RenderReportHeaderItem(pageHeader.ReportItemCollection[i], i, pageHeader.ReportItemCollection.Count);
                    sw.WriteLine(str);
                }               
                #endregion 

                sw.WriteLine("<table>");
                for (int i = 0; i <= report.Body.ReportItemCollection.Count - 1; i++)
                {
                    string str = RenderReportItem(report.Body.ReportItemCollection[i]);
                    sw.WriteLine(str);                    
                }

                //reset table row to start
                TableRenderer.curCellRow = 0;
                //TableRenderer.startPos = 0;
                TableRenderer.isStartRowReset = false;
                //TableRenderer.subreportStartRow = 0;
                //TableRenderer.subReportOffset = 0;
                //MatrixRenderer.isReadyForSumUp = false;
                TableRenderer.isRenderStartUp = false;
                TableRenderer.isInitSubreportStartRow = false;
                TextBoxFormulaHandler.tableOffset = 0;
                currentTableName = null;
                sw.WriteLine("</table>");
                sw.WriteLine("</body></html>");
                sw.Flush();
            }
            catch (Exception e)
            {
                throw new Exception("Error creating streams", e);
            }
            finally
            {
                if (sw != null)
                {
                    //closing the stream causes the report export to crash for some reason
                    //sw.Close();
                }
                if (s  != null)
                {
                    //closing the stream causes the report export to crash for some reason
                    //s .Close();
                }
            }

            //sw.Close();
            //s.Close();
           
			return false;
		}

        private void prepareReportRenderGlobalVariables(Microsoft.ReportingServices.ReportRendering.Report report)
        {
            string StreamRoot = HttpUtility.UrlDecode(report.Location.ToUri().AbsoluteUri);//"http://hornet/reportserver?/Insight/QA/";
            StreamRoot = StreamRoot.Replace(report.Name, "");
            //report.NeedsHeaderFooterEvaluation = false; 

            pageFooterWidth = report.PageFooter.Width.ToInches(); ;
            pageHeaderHeight = report.PageHeader.Height.ToInches();

            // if pageset is landscape
            if (report.PageWidth.ToInches() > report.PageHeight.ToInches())
                isWidePage = true;

            //string test = report.StreamURL(true, report.Name);
            reportFolder = report.Name;
            srvPath = HttpUtility.UrlDecode(report.Location.ToUri().AbsoluteUri);//"http://hornet/reportserver?/Insight/QA/";
            srvPath = StreamRoot.Replace(report.Name, "");

        }

        private void preparePageFooterItems()
        {
            // process report footer by adding stype to page

            for (int i = 0; i < pageFooter.ReportItemCollection.Count; i++)
            {
                loadReportFooter(pageFooter.ReportItemCollection[i]);
            }

  
                

        }

        /// <summary>
        /// prepare report print style, landscape or not, we need to set left footer, middle footer, 
        /// right footer values
        /// </summary>
        /// <returns>string</returns>
        private string getPageStyle()
        {
            pageFooterLeft = pageFooterLeft.Substring(0, pageFooterLeft.LastIndexOf("\\000A"));               
            return "<style> \n" +
                    "@page \n" +
                    "{\n" +
                    "mso-page-orientation:landscape;\n" +
                    "    mso-footer-data : '&L&8 " + pageFooterLeft +
                    " &C&8 " + pageFooterCenter +
                    " &R&8 " + pageFooterRight +
                    "';" +
                    "}\n" +
                    "</style>\n";
        }

        //private string getPageScript()
        //{
        //    string scripts = "<script language='javascipt'>"
        //                    + "function HtmlDecode(text)\n" 
        //                    + "{\n" 
        //                    + "var result = text;\n"
        //                    + " var amp = '&';\n"
        //                    + " var html_amp = /&amp;/gi;\n"
        //                    + "result = result.replace(html_amp, amp);\n"
        //                    + "return result;\n"
        //                    + "}"
        //                    + "</script>"
        //                    ;

        //    return scripts;
        //}

        private static string RenderReportHeaderItem(Microsoft.ReportingServices.ReportRendering.ReportItem reportItem, int iterator, int itemCount)
        {
            StringBuilder sb = new StringBuilder();
            if (iterator == 0)
                sb.Append("<table><tr>");

            string tdDef = getTDDef(reportItem);          

            sb.Append(tdDef);
            sb.Append(RenderReportItem(reportItem));
            sb.Append("</td>");

            if (iterator == itemCount - 1)
                sb.Append("</tr></table>");
 
            return sb.ToString();
        }

        /// <summary>
        ///     check report item width, get colspan property
        /// </summary>
        /// <param name="reportItem"></param>
        /// <returns></returns>
        protected static internal string getTDDef(Microsoft.ReportingServices.ReportRendering.ReportItem reportItem)
        {
            Double dColSpan = reportItem.Width.ToInches() / standardCellWidth;
            int colSpan = Convert.ToInt16(Math.Floor(dColSpan));

            string tdDef;

            if (colSpan > 1)
                tdDef = "<td colspan=\"" + colSpan + "\">";
            else
                tdDef = "<td>";

            return tdDef;
        }

        /// <summary>
        /// the RenderReportItem method check the type of report tiem being rendered
        /// and call the appropriate handling object
        /// </summary>
		protected internal static string RenderReportItem(Microsoft.ReportingServices.ReportRendering.ReportItem reportItem)
		{
			string pHtml = "";
            System.Type riType = reportItem.GetType();
            if (riType == typeof(Microsoft.ReportingServices.ReportRendering.Matrix) )
            {
                MatrixRenderer mr = new MatrixRenderer();
                pHtml = mr.Render((Microsoft.ReportingServices.ReportRendering.Matrix)reportItem);
            }
            else if (riType == typeof(Microsoft.ReportingServices.ReportRendering.Table))
            {
                TableRenderer tr = new TableRenderer();
                Microsoft.ReportingServices.ReportRendering.Table t = ((Microsoft.ReportingServices.ReportRendering.Table)reportItem);

                //TableRenderer.subreportStartRow += t.DetailRows == null? 0:(t.TableHeader == null ? 0 : 1 + (t.TableFooter == null ? 0 : 1) + (t.DetailRows == null ? 0 : t.DetailRows.Count));

                if (!TableRenderer.isInitSubreportStartRow)
                {
                    TableRenderer.subreportStartRow += (t.TableHeader == null ? 0 : t.TableHeader.Count) + (t.TableFooter == null ? 0 : t.TableFooter.Count) + (t.DetailRows == null ? 0 : t.DetailRows.Count);
                    TableRenderer.isInitSubreportStartRow = true;
                }

                if (t.Name != currentTableName && !isInSubreportContext)
                {
                    if (currentTableName == null)
                    {
                        currentTableName = t.Name;
                    }
                    else
                    {
                        TableRenderer.subreportStartRow += (t.TableHeader == null ? 0 : t.TableHeader.Count) + (t.TableFooter == null ? 0 : t.TableFooter.Count);   // +(t.DetailRows == null ? 0 : t.DetailRows.Count);
                        currentTableName = t.Name;
                    }
                    TextBoxFormulaHandler.tableOffset += (t.TableHeader == null ? 0 : t.TableHeader.Count) + (t.TableFooter == null ? 0 : t.TableFooter.Count) + (t.DetailRows == null ? 0 : t.DetailRows.Count) - 1;
                        
                }

                pHtml = tr.Render(t);
            }
            else if (riType == typeof(Microsoft.ReportingServices.ReportRendering.TextBox))
            {
                TextBoxRenderer tr = new TextBoxRenderer();
                if (!reportItem.Hidden)
                {
                    pHtml = tr.Render((Microsoft.ReportingServices.ReportRendering.TextBox)reportItem);
                }
                
            }
            else if (riType == typeof(Microsoft.ReportingServices.ReportRendering.Rectangle))
            {
                RectangleRenderer rr = new RectangleRenderer();
                pHtml = rr.Render((Microsoft.ReportingServices.ReportRendering.Rectangle)reportItem);
            }
            else if (riType == typeof(Microsoft.ReportingServices.ReportRendering.Image))
            {
                ImageRenderer ir = new ImageRenderer();
                pHtml = ir.Render((Microsoft.ReportingServices.ReportRendering.Image)reportItem);
            }
            else if (riType == typeof(Microsoft.ReportingServices.ReportRendering.List))
            {
                ListRenderer lr = new ListRenderer();
                pHtml = lr.Render((Microsoft.ReportingServices.ReportRendering.List)reportItem);
                //TableRenderer.subreportStartRow = 0;
            }
            else if (riType == typeof(Microsoft.ReportingServices.ReportRendering.SubReport))
            {
                SubreportRenderer sr = new SubreportRenderer();
                isInSubreportContext = true;
                pHtml = sr.Render((Microsoft.ReportingServices.ReportRendering.SubReport)reportItem);
                isInSubreportContext = false;                
            }
			return pHtml;
		}

        protected internal void loadReportFooter(Microsoft.ReportingServices.ReportRendering.ReportItem reportItem)
        {
            

            if (reportItem.GetType() == typeof(Microsoft.ReportingServices.ReportRendering.TextBox))
            {
                TextBox textBox = (TextBox)reportItem;
                string textBoxValue = textBox.Value;

                if (textBox.Formula != null && textBox.Formula.Contains("Globals.PageNumber"))
                    textBoxValue = "Page &P of &N";

                textBoxValue = "&\\0022" +
                    ((Microsoft.ReportingServices.ReportRendering.ReportItem)(textBox)).Style["FontFamily"] + "," +
                    ((Microsoft.ReportingServices.ReportRendering.ReportItem)(textBox)).Style["FontStyle"] +
                    "\\0022" + textBoxValue;

                double textBoxWidth = textBox.Left.ToInches();
                if (textBoxWidth < pageFooterWidth / 3)
                    pageFooterLeft += textBoxValue + "\\000A";
                else if ((textBoxWidth >= pageFooterWidth / 3) && (textBoxWidth < pageFooterWidth * 2 / 3))
                    pageFooterCenter += textBoxValue + "\\000A";
                else
                    pageFooterRight += textBoxValue + "\\000A";
            }
        }

        private string pagePrintDef 
        {
            get {
                return (_pagePrintDef == "" ? "<!--[if gte mso 9]><xml>\n" +
                                        "<x:ExcelWorkbook>\n" +
                                        "<x:ExcelWorksheets>\n" +
                                        "<x:ExcelWorksheet>\n" +
                                        "<x:WorksheetOptions>\n" +
                                        "<x:Print>\n" +
                                        "<x:ValidPrinterInfo/>\n" +
                                        "<x:PaperSizeIndex>9</x:PaperSizeIndex>\n" +
                                        "<x:HorizontalResolution>600</x:HorizontalResolution>\n" +
                                        "<x:VerticalResolution>600</x:VerticalResolution>\n" +
                                        "</x:Print>\n" +
                                        "<x:Selected/>\n" +
                                        "<x:DoNotDisplayGridlines/>\n" +
                                        "<x:ProtectContents>False</x:ProtectContents>\n" +
                                        "<x:ProtectObjects>False</x:ProtectObjects>\n" +
                                        "<x:ProtectScenarios>False</x:ProtectScenarios>\n" +
                                        "</x:WorksheetOptions>\n" +
                                        "</x:ExcelWorksheet>\n" +
                                        "</x:ExcelWorksheets>\n" +
                                        "<x:WindowHeight>12780</x:WindowHeight>\n" +
                                        "<x:WindowWidth>19035</x:WindowWidth>\n" +
                                        "<x:WindowTopX>0</x:WindowTopX>\n" +
                                        "<x:WindowTopY>15</x:WindowTopY>\n" +
                                        "<x:ProtectStructure>False</x:ProtectStructure>\n" +
                                        "<x:ProtectWindows>False</x:ProtectWindows>\n" +
                                        "</x:ExcelWorkbook>\n" +
                                        "</xml><![endif]-->" : _pagePrintDef);
            }
            set {
                _pagePrintDef = value;
            }
        }

		public void GetRenderingResource(Microsoft.ReportingServices.Interfaces.CreateAndRegisterStream createAndRegisterStreamCallback, System.Collections.Specialized.NameValueCollection deviceInfo)
		{
			//Render any Embedded Resource in the Report
            // deviceInfo.Keys.Count ;
		}
		
		public string LocalizedName
		{
			get
			{
				//A Read only properties which return the name of
				//this RS extension
				string p_strName = "Custom Excel Renderer";
				
				System.Globalization.CultureInfo p_CultureInfo = System.Globalization.CultureInfo.CurrentCulture;
				
				//Determine the text to be returned (displayed) by
				// the Name property of CultureInfo class
				if (p_CultureInfo.Name == "zh-HK")
				{
					p_strName += " (Traditional Chinese)";
					
					
				}
				else if (p_CultureInfo.Name == "zh-CN")
				{
					
					p_strName += " (Simplified Chinese)";
				}
				return p_strName;
			}
			
		}
		
		
		public void SetConfiguration(string configuration)
		{
			//Used to pass configuration from Reporting Services Config File
			//to this Reporting Serivces Extension
		}

        /// <summary>
        /// hash table used to hold report position and location data
        /// </summary>
        internal static Hashtable reportItemHashTable;
        /// <summary>
        /// record used by Renderer object to track report items being processed
        /// </summary>
        internal static ReportRenderCache reportRenderCache;
		
	}
	
}
